
#include "Mxd0250OAL.h"

#include "nxml.h"

typedef struct{
	MXD_UINT8* pos;
	MXD_UINT32 len;
}_struct_mem_list;

typedef struct{
	MXD_UINT8* pos;
	MXD_UINT32 len;
	MXD_UINT8 valid;
}_struct_mem_list2;

static MXD_UINT8* _mem_pool = NULL;
static _struct_mem_list *_mem_free_list= NULL;
static _struct_mem_list2 *_mem_used_list= NULL;
static MXD_UINT32 _mem_free_count=0, _mem_used_count=0;
static MXD_UINT8 _eaten_byte = 0;

static void _mxd_fast_mem_init(MXD_UINT32 bufsize)
{
	if( _mem_pool )
		MXD_DebugPrint( "the mem pool is not empty!\n" );
	_mem_pool = (MXD_UINT8*)MXD_Malloc( bufsize*4 );
	_mem_free_list = (_struct_mem_list*) MXD_Malloc( sizeof(_struct_mem_list)*bufsize/10 );
	_mem_used_list = (_struct_mem_list2*) MXD_Malloc( sizeof(_struct_mem_list2)*bufsize/7 );
	_mem_used_count = 0;
	_mem_free_count = 1;
	_mem_free_list[0].pos = _mem_pool;
	_mem_free_list[0].len = bufsize*4;
	//MXD_DebugPrint("pool =%x, used=%x, free=%x\n",_mem_pool,_mem_used_list,_mem_free_list);
}

static void _mxd_fast_mem_destory( void )
{
	MXD_UINT32 i;

	if( _mem_free_count == 0 && _mem_used_count == 0 )
		return;

	for( i=0; i<_mem_used_count; i++ )
	{
		if( _mem_used_list[i].valid == 1 )
		{
			//MXD_DebugPrint( "not all reference to mem are released!\n" );
			break;
		}
	}
	MXD_Free( _mem_pool );
	MXD_Free( _mem_free_list );
	MXD_Free( _mem_used_list );
	_mem_pool = NULL;
	_mem_free_list= NULL;
	_mem_used_list= NULL;
	_mem_free_count=0;
	_mem_used_count=0;
}

static MXD_INT g_memsize=0;
static void* _mxd_fast_malloc(MXD_UINT32 msize)
{
	MXD_UINT32 i;
	void* retPnt = NULL;
	if( msize %4 )
		msize = (msize /4 + 1) *4;
	g_memsize+=msize;
	//MXD_DebugPrint("malloc %d, allocate mem %d, _mem_free_count=%d, _mem_used_count=%d\n", msize,g_memsize,_mem_free_count, _mem_used_count);
	for( i=0; i<_mem_free_count; i++ )
	{
		if( _mem_free_list[i].len >= msize )
		{
			retPnt = _mem_free_list[i].pos;
			_mem_free_list[i].pos += msize;
			_mem_free_list[i].len -= msize;
			break;
		}
	}
	if( !retPnt )
		return NULL;
	_mem_used_list[_mem_used_count].pos = retPnt;
	_mem_used_list[_mem_used_count].len = msize;
	_mem_used_list[_mem_used_count].valid = 1;
	_mem_used_count++;
	return retPnt;
}

static void _mxd_fast_free(void *pmem)
{
#if 0
	MXD_UINT32 i;
	MXD_UINT32 msize=0;

	for( i=0; i<_mem_used_count; i++ )
	{
		if( pmem == _mem_used_list[i].pos && _mem_used_list[i].valid == 1 )
		{
			msize = _mem_used_list[i].len;
			_mem_used_list[i].valid = 0;
			break;
		}
	}
	g_memsize-=msize;

	for( i=0; i<_mem_free_count; i++ )
	{
		if( pmem == _mem_free_list[i].pos + _mem_free_list[i].len )
		{
			_mem_free_list[i].len += msize;
			return;
		}
		if( (MXD_UINT8*)pmem + msize == _mem_free_list[i].pos )
		{
			_mem_free_list[i].pos = pmem;
			_mem_free_list[i].len += msize;
			return;
		}
	}
	_mem_free_list[_mem_free_count].pos = pmem;
	_mem_free_list[_mem_free_count].len = msize;
	_mem_free_count++;
#endif
}

static MXD_CHAR *_mxd_fast_strdup(MXD_CHAR *s)
{
	MXD_CHAR *pNewStr;
	if( s == NULL )
		return NULL;
	pNewStr = (MXD_CHAR *)_mxd_fast_malloc( MXD_Strlen(s) + 1 );
	MXD_Strcpy( pNewStr, s);
	return pNewStr;
}

static void *_mxd_calloc(MXD_INT nelem, MXD_INT elsize)
{
	void* pTmp;
	pTmp = _mxd_fast_malloc( nelem*elsize );
	MXD_Memset( pTmp, 0, nelem*elsize );
	return pTmp;
}

static MXD_INT _mxd_strncmp( MXD_CHAR * _Str1, MXD_CHAR * _Str2, MXD_INT _MaxCount)
{
	MXD_INT i;
	for( i=0; i<_MaxCount; i++ )
	{
		if( _Str1[i] > _Str2[i] )
			return 1;
		else if( _Str1[i] < _Str2[i] )
			return -1;
	}
	return 0;
}
/*
static MXD_INT
__nxml_parse_unique_attribute (nxml_attr_t * attr, MXD_CHAR *name)
{
	/ * 
	* Rule [40] - Well-formedness contraint: Unique Att Spec
	* /

	while (attr)
	{
		if (!MXD_Strcmp (attr->name, name))
			return 1;

		attr = attr->next;
	}

	return 0;
}
*/

static MXD_CHAR *
__nxml_parse_string (nxml_t * doc, MXD_CHAR *buffer, MXD_INT size)
{
	MXD_CHAR* newstr;
	newstr = _mxd_fast_malloc( size + 1 );
	MXD_Memcpy( newstr, buffer, size );
	newstr[size] = 0;
	return newstr;
}

static MXD_INT check_name_start_char( MXD_UINT8 ch)
{
	return (ch == ':') \
		|| (ch >= 'a' && ch <= 'z') \
		|| (ch=='_') \
		|| (ch >= 'A' && ch <= 'Z') \
		|| (ch >= 0xc0 && ch <= 0xd6) \
		|| (ch >= 0xd8 && ch <= 0xf6);
}

static MXD_INT check_name_char( MXD_UINT8 ch)
{
	return (ch == ':') \
		|| (ch >= 'a' && ch <= 'z') \
		|| (ch=='_') \
		|| (ch >= 'A' && ch <= 'Z') \
		|| (ch >= 0xc0 && ch <= 0xd6) \
		|| (ch >= 0xd8 && ch <= 0xf6) \
		|| (ch=='-') \
		|| (ch=='.') \
		|| (ch >= '0' && ch <= '9') \
		|| (ch==0xb7) ;
}

static MXD_CHAR *
__nxml_parse_get_attr (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size)
{
	MXD_CHAR attr[1024];
	MXD_INT i;
	MXD_CHAR* new_attr;
	//MXD_INT byte=1;
	//MXD_INT ch;

	if (!*size)
		return NULL;

	if (!check_name_start_char(**buffer))
		return NULL;

	new_attr = *buffer;

	for( i=0; i<sizeof (attr)-1; i++ )
	{
		//*(attr+i) = **buffer;
		(*buffer) ++;
		(*size) --;
		if( !(check_name_char(**buffer)) )
		{
			i++;
			break;
		}
		if( *size == 0 )
			break;
	}

	if (**buffer != 0x20 && **buffer != 0x9 && **buffer != 0xa
		&& **buffer != 0xd && **buffer != '=')
	{
		(*buffer) -= i;
		(*size) += i;
		return NULL;
	}

	i += __nxml_escape_spaces (doc, buffer, size);

	if (**buffer != '=')
	{
		(*buffer) -= i;
		(*size) += i;
		return NULL;
	}

	(*buffer)++;
	(*size)--;

	__nxml_escape_spaces (doc, buffer, size);

	new_attr[i] = 0;
	//attr[i] = 0;
	return new_attr; //_mxd_fast_strdup (attr);
}

static nxml_error_t
__nxml_parse_get_attribute (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
							nxml_attr_t ** attr)
{
	/* 
	* Rule [41] - Attribute ::= Name Eq AttValue
	* Rule [25] - Eq ::= S? '=' S?
	* Rule [5]  - Name ::= NameStartChar (NameChar)*
	* Rule [4]  - NameStartChar ::= ":" | [A-Z] | ["_"] | [a-z] | Unicode...
	* Rule [4a] - NameChar ::= NameStarChar | "-" | "." | [0-9] | Unicode...
	* Rule [10] - AttValue ::= '"' ([^<&"] | Reference)* '"' |
	*                          "'" ([^<&'] | Reference)* "'"
	*/
	MXD_CHAR *tag, *value;//, *v;

	if (!*size)
		return NXML_OK;

	*attr = NULL;

	__nxml_escape_spaces (doc, buffer, size);
	tag = __nxml_parse_get_attr (doc, buffer, size);
	if (!tag)
		return NXML_OK;

	value = __nxml_get_value (doc, buffer, size);
	if (!value)
	{
		_mxd_fast_free (tag);

		if (doc->priv.func)
			doc->priv.func ("%s: expected value of attribute (line %d)\n",
			doc->file ? doc->file : "", doc->priv.line);
		return NXML_ERR_PARSER;
	}

	__nxml_escape_spaces (doc, buffer, size);

	*attr = (nxml_attr_t *) _mxd_calloc (1, sizeof (nxml_attr_t));
	if (!(*attr))
	{
		_mxd_fast_free (tag);
		_mxd_fast_free (value);

		return NXML_ERR_POSIX;
	}

	(*attr)->name = tag;
	(*attr)->value = value;

	return NXML_OK;
}

static nxml_error_t
__nxml_parse_cdata (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
					nxml_data_t ** data)
{
	/*
	* Rule [18] - CDSect ::= CDStart CData CDEnd 
	* Rule [19] - CDStart ::= '<![CDATA['
	* Rule [20] - CData ::= (Char * - (Char * ']]>' Char *))
	* Rule [21] - CDEnd ::= ']]>'
	*/

	MXD_INT i = 0;
	nxml_data_t *t;
	MXD_CHAR *value;

	while (i < *size)
	{
		if (!_mxd_strncmp (*buffer + i, "]]>", 3))
			break;

		if (*(*buffer + i) == 0xa && doc->priv.func)
			doc->priv.line++;

		i++;
	}

	if (_mxd_strncmp (*buffer + i, "]]>", 3))
	{
		if (doc->priv.func)
			doc->priv.func ("%s: expected ']]>' as close of a CDATA (line %d)\n",
			doc->file ? doc->file : "", doc->priv.line);

		return NXML_ERR_PARSER;
	}

	t = (nxml_data_t *) _mxd_calloc (1, sizeof (nxml_data_t));
	if (!t)
		return NXML_ERR_POSIX;

	t->doc = doc;

	value = (MXD_CHAR *) _mxd_fast_malloc (sizeof (MXD_CHAR) * (i + 1));
	if (!value)
	{
		_mxd_fast_free (t);
		return NXML_ERR_POSIX;
	}

	MXD_Memcpy (value, *buffer, i);
	value[i] = 0;

	t->value = value;
	t->type = NXML_TYPE_TEXT;

	(*buffer) += i + 3;
	(*size) -= i + 3;

	*data = t;

	return NXML_OK;
}

static void
__nxml_parse_entity (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size)
{
	/*
	* [70]       EntityDecl ::=          GEDecl | PEDecl
	* [71]       GEDecl     ::=          '<!ENTITY' S Name S EntityDef S? '>'
	* [72]       PEDecl     ::=          '<!ENTITY' S '%' S Name S PEDef S? '>'
	* [73]       EntityDef  ::=          EntityValue | (ExternalID NDataDecl?)
	* [74]       PEDef      ::=          EntityValue | ExternalID
	*/

	MXD_INT i;
	MXD_CHAR name[1024];
	MXD_CHAR *entity;
	//MXD_INT byte;
	//MXD_INT ch;

	__nxml_escape_spaces (doc, buffer, size);

	if (_mxd_strncmp (*buffer, "<!ENTITY", 8))
	{
		MXD_INT q = i = 0;

		while ((*(*buffer + i) != '>' || q) && i < *size)
		{
			if (*(*buffer + i) == '<')
				q++;

			else if (*(*buffer + i) == '>')
				q--;

			i++;
		}

		if (*(*buffer) == '>')
			i++;

		(*buffer) += i;
		(*size) -= i;
		return;
	}

	*buffer += 8;
	*size -= 8;

	__nxml_escape_spaces (doc, buffer, size);

	/* Name */
	if (!check_name_start_char(**buffer))
	{
		MXD_INT q = i = 0;

		while ((*(*buffer + i) != '>' || q) && i < *size)
		{
			if (*(*buffer + i) == '<')
				q++;

			else if (*(*buffer + i) == '>')
				q--;

			i++;
		}

		if (*(*buffer) == '>')
			i++;

		(*buffer) += i;
		(*size) -= i;
		return;
	}

	for( i=0; i<sizeof (name)-1; i++ )
	{
		*(name+i) = **buffer;
		(*buffer) ++;
		(*size) --;
		if( !(check_name_char(**buffer)) )
		{
			i++;
			break;
		}
		if( *size == 0 )
			break;
	}
	name[i] = 0;

	if (!i || (*name != '%'))
	{
		MXD_INT q = i = 0;

		while ((*(*buffer + i) != '>' || q) && i < *size)
		{
			if (*(*buffer + i) == '<')
				q++;

			else if (*(*buffer + i) == '>')
				q--;

			i++;
		}

		if (*(*buffer) == '>')
			i++;

		(*buffer) += i;
		(*size) -= i;
		return;
	}

	__nxml_escape_spaces (doc, buffer, size);

	entity = __nxml_get_value (doc, buffer, size);

	__nxml_escape_spaces (doc, buffer, size);

	if (**buffer == '>')
	{
		(*buffer)++;
		(*size)--;
	}

	if (entity)
	{
		__nxml_entity_t *e;

		e = (__nxml_entity_t *) _mxd_calloc (1, sizeof (__nxml_entity_t));
		if (!e)
		{
			_mxd_fast_free (entity);
			return;
		}

		e->name = _mxd_fast_strdup (name);
		if (!e->name)
		{
			_mxd_fast_free (e);
			_mxd_fast_free (entity);
			return;
		}

		e->entity = entity;

		if (!doc->priv.entities)
			doc->priv.entities = e;
		else
		{
			__nxml_entity_t *tmp = doc->priv.entities;

			while (tmp->next)
				tmp = tmp->next;

			tmp->next = e;
		}
	}
}

static nxml_error_t
__nxml_parse_doctype (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
					  MXD_INT *doctype)
{
	/*
	* Rule [28] - doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? 
	*                             ('[' intSubset '] S?)? '>'
	*/

	nxml_doctype_t *t;
	nxml_doctype_t *tmp;
	MXD_CHAR str[1024];
	MXD_CHAR *value;
	MXD_INT i;
	//MXD_INT byte;
	//MXD_INT ch;
	MXD_INT q = 0;

	__nxml_escape_spaces (doc, buffer, size);

	if (!check_name_start_char(**buffer))
	{
		if (doc->priv.func)
			doc->priv.func ("%s: abnormal MXD_CHAR '%c' (line %d)\n",
			doc->file ? doc->file : "", **buffer, doc->priv.line);
		return NXML_ERR_PARSER;
	}

	for( i=0; i<sizeof (str)-1; i++ )
	{
		*(str+i) = **buffer;
		(*buffer) ++;
		(*size) --;
		if( !(check_name_char(**buffer)) )
		{
			i++;
			break;
		}
		if( *size == 0 )
			break;
	}
	str[i] = 0;

	t = (nxml_doctype_t *) _mxd_calloc (1, sizeof (nxml_doctype_t));
	if (!t)
		return NXML_ERR_POSIX;

	t->doc = doc;

	t->name = _mxd_fast_strdup (str);
	if (!t->name)
	{
		_mxd_fast_free (t);
		return NXML_ERR_POSIX;
	}

	__nxml_escape_spaces (doc, buffer, size);

	i = 0;
	while ((*(*buffer + i) != '>' || q) && i < *size)
	{
		if (*(*buffer + i) == '<')
			q++;

		else if (*(*buffer + i) == '>')
			q--;

		if (*(*buffer + i) == 0xa && doc->priv.func)
			doc->priv.line++;

		i++;
	}

	if (*(*buffer + i) != '>')
	{
		if (doc->priv.func)
			doc->priv.func ("%s: expected '>' as close of a doctype (line %d)\n",
			doc->file ? doc->file : "", doc->priv.line);

		_mxd_fast_free (t->value);
		_mxd_fast_free (t);
		return NXML_ERR_PARSER;
	}

	value = __nxml_parse_string (doc, *buffer, i);
	if (!value)
	{
		_mxd_fast_free (t->value);
		_mxd_fast_free (t);
		return NXML_ERR_POSIX;
	}

	t->value = value;

	(*buffer) += i + 1;
	(*size) -= i + 1;

	tmp = doc->doctype;
	if (!tmp)
		doc->doctype = t;

	else
	{
		while (tmp->next)
			tmp = tmp->next;

		tmp->next = t;
	}

	*doctype = 1;

	while (value && *value && *value != '[')
		value++;

	if (value && *value == '[')
	{
		MXD_UINT size;

		value++;
		size = MXD_Strlen (value);

		while (size > 0 && value && *value)
			__nxml_parse_entity (doc, &value, (MXD_UINT32 *) & size);
	}

	return NXML_OK;
}

static nxml_error_t
__nxml_parse_comment (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
					  nxml_data_t ** data)
{
	/* 
	* Rule [15] - Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
	*/

	MXD_INT i = 0;
	nxml_data_t *t;
	MXD_CHAR *value;

	while (_mxd_strncmp (*buffer + i, "-->", 3) && i < *size)
	{
		if (*(*buffer + i) == 0xa && doc->priv.func)
			doc->priv.line++;
		i++;
	}

	if (_mxd_strncmp (*buffer + i, "-->", 3))
	{
		if (doc->priv.func)
			doc->priv.func ("%s: expected '--' as close comment (line %d)\n",
			doc->file ? doc->file : "", doc->priv.line);

		return NXML_ERR_PARSER;
	}

	t = (nxml_data_t *) _mxd_calloc (1, sizeof (nxml_data_t));
	if (!t)
		return NXML_ERR_POSIX;

	t->doc = doc;

	value = __nxml_parse_string (doc, *buffer, i);
	if (!value)
	{
		_mxd_fast_free (t);
		return NXML_ERR_POSIX;
	}

	t->value = value;

	(*buffer) += i + 3;
	(*size) -= i + 3;

	t->type = NXML_TYPE_COMMENT;

	*data = t;

	return NXML_OK;
}

static nxml_error_t
__nxml_parse_pi (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
				 nxml_data_t ** data)
{
	/* 
	* Rule [16] - PI ::= '<?' PITarget (S (Char * - (Char * '?>' Char *)))? 
	*                    '?>'
	* Rule [17] - PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
	*/

	MXD_INT i = 0;
	nxml_data_t *t;
	MXD_CHAR *value;

	if (!*size)
		return NXML_OK;

	*data = NULL;

	(*buffer) += 1;
	(*size) -= 1;

	while (_mxd_strncmp (*buffer + i, "?>", 2) && i < *size)
	{
		if (*(*buffer + i) == 0xa && doc->priv.func)
			doc->priv.line++;
		i++;
	}

	if (_mxd_strncmp (*buffer + i, "?>", 2))
	{
		if (doc->priv.func)
			doc->priv.func ("%s: expected '?' as close pi tag (line %d)\n",
			doc->file ? doc->file : "", doc->priv.line);

		return NXML_ERR_PARSER;
	}

	if (!_mxd_strncmp (*buffer, "?xml", 4)) //todo: david!
	{
		if (doc->priv.func)
			doc->priv.func ("%s: pi xml is reserved! (line %d)\n",
			doc->file ? doc->file : "", doc->priv.line);

		return NXML_ERR_PARSER;
	}

	t = (nxml_data_t *) _mxd_calloc (1, sizeof (nxml_data_t));
	if (!t)
		return NXML_ERR_POSIX;

	t->doc = doc;

	value = __nxml_parse_string (doc, *buffer, i);
	if (!value)
	{
		_mxd_fast_free (t);
		return NXML_ERR_POSIX;
	}

	t->value = value;

	(*buffer) += i + 2;
	(*size) -= i + 2;

	t->type = NXML_TYPE_PI;

	*data = t;

	return NXML_OK;
}

static nxml_error_t
__nxml_parse_other (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
					nxml_data_t ** data, MXD_INT *doctype)
{
	/* Tags '<!'... */

	*data = NULL;
	*doctype = 0;

	if (!*size)
		return NXML_OK;

	(*buffer) += 1;
	(*size) -= 1;

	__nxml_escape_spaces (doc, buffer, size);

	if (!_mxd_strncmp (*buffer, "[CDATA[", 7))
	{
		(*buffer) += 7;
		(*size) -= 7;

		return __nxml_parse_cdata (doc, buffer, size, data);
	}

	else if (!_mxd_strncmp (*buffer, "--", 2))
	{
		(*buffer) += 2;
		(*size) -= 2;

		return __nxml_parse_comment (doc, buffer, size, data);
	}

	else if (!_mxd_strncmp (*buffer, "DOCTYPE", 7))
	{
		(*buffer) += 7;
		(*size) -= 7;

		return __nxml_parse_doctype (doc, buffer, size, doctype);
	}

	else
	{
		if (doc->priv.func)
			doc->priv.func ("%s: abnormal tag (line %d)\n",
			doc->file ? doc->file : "", doc->priv.line);

		return NXML_ERR_PARSER;
	}
}

static nxml_error_t
__nxml_parse_text (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
				   nxml_data_t ** data)
{
	MXD_INT i = 0;
	nxml_data_t *t;
	MXD_CHAR *value;
	MXD_CHAR *value_new;

	*data = NULL;

	if (!*size)
		return NXML_OK;

	while (*(*buffer + i) != '<' && i < *size)
	{
		if (*(*buffer + i) == 0xa && doc->priv.func)
			doc->priv.line++;
		i++;
	}

	t = (nxml_data_t *) _mxd_calloc (1, sizeof (nxml_data_t));
	if (!t)
		return NXML_ERR_POSIX;

	t->doc = doc;

	_eaten_byte = *(*buffer+i);
#if 0
	if (!(value = __nxml_parse_string (doc, *buffer, i)))
	{
		_mxd_fast_free (t);
		return NXML_ERR_POSIX;
	}
#endif
	value = *buffer;
	*(*buffer+i) = 0;

	(*buffer) += i;
	(*size) -= i;

	value_new = __nxml_trim (value);
	//_mxd_fast_free (value);

	if (!value_new)
	{
		_mxd_fast_free (t);
		return NXML_ERR_POSIX;
	}

	t->value = value_new;
	t->type = NXML_TYPE_TEXT;

	*data = t;

	return NXML_OK;
}

static nxml_error_t
__nxml_parse_close (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
					nxml_data_t ** data)
{
	/* 
	* Rule [42] - ETag ::= '</' Name S? '>'
	*/

	nxml_data_t *tag;
	//MXD_CHAR str[1024];
	MXD_INT i;
	//MXD_INT byte;
	//MXD_INT ch;
	MXD_CHAR* pValue;

	*data = NULL;

	if (!*size)
		return NXML_OK;

	if (!check_name_start_char(**buffer))
	{
		if (doc->priv.func)
			doc->priv.func ("%s: abnormal MXD_CHAR '%c' (line %d)\n",
			doc->file ? doc->file : "", **buffer, doc->priv.line);
		return NXML_ERR_PARSER;
	}

	pValue = *buffer;

#if 0
	for( i=0; i<sizeof (str)-1; i++ )
	{
		*(str+i) = **buffer;
		(*buffer) ++;
		(*size) --;
		if( !(check_name_char(**buffer)) )
		{
			i++;
			break;
		}
		if( *size == 0 )
			break;
	}
	str[i] = 0;
#endif
	for( i=0; i<200; i++ )
	{
		(*buffer) ++;
		(*size) --;
		if( !(check_name_char(**buffer)) )
		{
			i++;
			break;
		}
		if( *size == 0 )
			break;
	}

	__nxml_escape_spaces (doc, buffer, size);

	if (**buffer != '>')
	{
		//if (doc->priv.func)
		//	doc->priv.func ("%s: expected MXD_CHAR '>' after tag %s (line %d)\n",
		//	doc->file ? doc->file : "", str, doc->priv.line);
		return NXML_ERR_PARSER;
	}
	pValue[i] = 0;

	(*buffer) += 1;
	(*size) -= 1;

	tag = (nxml_data_t *) _mxd_calloc (1, sizeof (nxml_data_t));
	if (!tag)
		return NXML_ERR_POSIX;

	tag->doc = doc;
#if 0
	if (!(tag->value = _mxd_fast_strdup (str)))
	{
		_mxd_fast_free (tag);
		return NXML_ERR_POSIX;
	}
#endif
	tag->value = pValue;

	tag->type = NXML_TYPE_ELEMENT_CLOSE;

	*data = tag;

	return NXML_OK;
}

static nxml_error_t
__nxml_parse_get_tag (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size,
					  nxml_data_t ** data, MXD_INT *doctype)
{
	/* Parse the element... */
	nxml_attr_t *attr, *last;
	nxml_data_t *tag, *child, *child_last;
	nxml_error_t err;

	//MXD_CHAR str[1024];
	MXD_INT i;
	MXD_INT closed = 0;
	//MXD_INT byte;
	//MXD_INT ch;
	MXD_CHAR* pValue;

	*data = NULL;
	*doctype = 0;

	if (!*size)
		return NXML_OK;

	__nxml_escape_spaces (doc, buffer, size);

	/* Text */
	if (**buffer != '<' && _eaten_byte != '<' )
	{
		return __nxml_parse_text (doc, buffer, size, data);
	}
	_eaten_byte = 0;

	(*buffer) += 1;
	(*size) -= 1;

	/* Comment, CData, DocType or other elements */
	if (**buffer == '!')
		return __nxml_parse_other (doc, buffer, size, data, doctype);

	/* PI */
	else if (**buffer == '?')
		return __nxml_parse_pi (doc, buffer, size, data);

	/* Close tag */
	else if (**buffer == '/')
	{
		(*buffer) += 1;
		(*size) -= 1;
		return __nxml_parse_close (doc, buffer, size, data);
	}

	__nxml_escape_spaces (doc, buffer, size);

	if (!check_name_start_char(**buffer))
	{
		if (doc->priv.func)
			doc->priv.func ("%s: abnormal MXD_CHAR '%c' (line %d)\n",
			doc->file ? doc->file : "", **buffer, doc->priv.line);
		return NXML_ERR_PARSER;
	}

	pValue = *buffer;

#if 0
	for( i=0; i<sizeof (str)-1; i++ )
	{
		*(str+i) = **buffer;
		(*buffer) ++;
		(*size) --;
		if( !(check_name_char(**buffer)) )
		{
			i++;
			break;
		}
		if( *size == 0 )
			break;
	}
	str[i] = 0;
#endif
	for( i=0; i<200; i++ )
	{
		(*buffer) ++;
		(*size) --;
		if( !(check_name_char(**buffer)) )
		{
			i++;
			break;
		}
		if( *size == 0 )
			break;
	}

	if (**buffer != 0x20 && **buffer != 0x9 && **buffer != 0xa
		&& **buffer != 0xd && **buffer != '>' && **buffer != '/')
	{
		(*buffer) -= i;
		(*size) += i;

//		if (doc->priv.func)
//			doc->priv.func ("%s: abnormal MXD_CHAR '%c' after tag %s (line %d)\n",
//			doc->file ? doc->file : "", *(*buffer + i), str,
//			doc->priv.line);

		return NXML_ERR_PARSER;
	}

	tag = (nxml_data_t *) _mxd_calloc (1, sizeof (nxml_data_t));
	if (!tag)
		return NXML_ERR_POSIX;

	tag->doc = doc;
#if 0
	if (!(tag->value = _mxd_fast_strdup (str)))
	{
		_mxd_fast_free (tag);
		return NXML_ERR_POSIX;
	}
#endif
	tag->value = pValue;

	last = NULL;

	/* Get attribute: */
	while (!(err = __nxml_parse_get_attribute (doc, buffer, size, &attr))
		&& attr)
	{
		if (!*size)
			return NXML_ERR_PARSER;
#if 0
		if (__nxml_parse_unique_attribute (tag->attributes, attr->name))
		{
			if (doc->priv.func)
				doc->priv.
				func ("%s: Duplicate attribute '%s' in tag '%s' (line %d)\n",
				doc->file ? doc->file : "", attr->name, tag->value,
				doc->priv.line);

			nxml_free_attribute (attr);
			nxml_free_data (tag);

			return NXML_ERR_PARSER;
		}
#endif
		if (last)
			last->next = attr;
		else
			tag->attributes = attr;

		last = attr;
	}

	if (err)
	{
		nxml_free_data (tag);
		return err;
	}

	/* Closed element */
	if (**buffer == '/')
	{
		closed++;
		(*buffer) += 1;
		(*size) -= 1;

		__nxml_escape_spaces (doc, buffer, size);
	}

#if 1
	if (**buffer != '>')
	{
		if (doc->priv.func)
			doc->priv.func ("%s: expected char '>' after tag %s (line %d)\n",
			doc->file ? doc->file : "", tag->value,
			doc->priv.line);

		nxml_free_data (tag);
		return NXML_ERR_PARSER;
	}
#endif

	pValue[i] = 0;
	(*buffer) += 1;
	(*size) -= 1;

	if (!closed)
	{
		child_last = NULL;

		/* Search children: */
		while (!
			(err = __nxml_parse_get_tag (doc, buffer, size, &child, doctype))
			&& (*doctype || child))
		{
			if (*doctype)
				continue;

			/* If the current child, break: */
			if (child->type == NXML_TYPE_ELEMENT_CLOSE)
			{
				if (!MXD_Strcmp (child->value, tag->value))
				{
					closed = 1;
					nxml_free_data (child);
					break;
				}

				else
				{
					if (doc->priv.func)
						doc->priv.
						func ("%s: expected tag '/%s' and not '%s' (line %d)\n",
						doc->file ? doc->file : "", tag->value,
						child->value, doc->priv.line);

					nxml_free_data (child);
					nxml_free_data (tag);

					return NXML_ERR_PARSER;
				}
			}

			/* Set the parent */
			child->parent = tag;

			if (child_last)
				child_last->next = child;
			else
				tag->children = child;

			child_last = child;
		}

		if (err)
		{
			nxml_free_data (tag);
			return err;
		}
	}

	tag->type = NXML_TYPE_ELEMENT;

	if (!closed)
	{
		if (doc->priv.func)
			doc->priv.func ("%s: expected tag '/%s' (line %d)\n",
			doc->file ? doc->file : "", tag->value,
			doc->priv.line);

		nxml_free_data (tag);
		return NXML_ERR_PARSER;
	}

	*data = tag;
	return NXML_OK;
}

static nxml_error_t
__nxml_parse_buffer (nxml_t * nxml, MXD_CHAR *r_buffer, MXD_UINT32 r_size)
{
	/* 
	* Rule [1] - Document ::= prolog element Misc* - Char* RestrictedChar Char*
	*/

	nxml_attr_t *attr;
	nxml_error_t err;
	nxml_charset_t charset=NXML_CHARSET_UTF8;
	nxml_data_t *tag, *last, *root;
	MXD_INT doctype;

	MXD_INT freed=0;

	MXD_CHAR *buffer = NULL;
	MXD_UINT32 size;

	if (!r_buffer || !nxml)
		return NXML_ERR_DATA;

	if (!r_size)
		r_size = MXD_Strlen (r_buffer);

	//switch ((freed =
	//  __nxml_utf_detection (r_buffer, r_size, &buffer, &size, &charset)))
	//  {
	//  case 0:
	buffer = r_buffer;
	size = r_size;
	//    break;

	//  case -1:
	//    return NXML_ERR_POSIX;
	//  }

	nxml->priv.line = 1;
	nxml->version = NXML_VERSION_1_0;
	nxml->standalone = 1;
	nxml->priv.func = MXD_DebugPrint;

	/* 
	* Rule [22] - prolog ::= XMLDecl Misc* (doctypedecl Misc*)?
	* Rule [23] - XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
	*/
	if (!_mxd_strncmp (buffer, "<?xml ", 6))
	{
		buffer += 6;
		size -= 6;

		if ((err =
			__nxml_parse_get_attribute (nxml, &buffer, &size,
			&attr)) != NXML_OK)
		{
			nxml_empty (nxml);

			if (freed)
				_mxd_fast_free (buffer);

			return err;
		}

		if (!attr)
		{
			if (nxml->priv.func)
				nxml->priv.func ("%s: expected 'version' attribute (line %d)\n",
				nxml->file ? nxml->file : "", nxml->priv.line);

			if (freed)
				_mxd_fast_free (buffer);

			return NXML_ERR_PARSER;
		}

		if (!MXD_Strcmp (attr->value, "1.0"))
			nxml->version = NXML_VERSION_1_0;

		else if (!MXD_Strcmp (attr->value, "1.1"))
			nxml->version = NXML_VERSION_1_1;

		else
		{
			if (nxml->priv.func)
				nxml->priv.
				func (  " suports only xml 1.1 or 1.0 (line %d)\n",
				nxml->priv.line);

			if (freed)
				_mxd_fast_free (buffer);

			return NXML_ERR_PARSER;
		}

		nxml_free_attribute (attr);

		while (!(err = __nxml_parse_get_attribute (nxml, &buffer, &size, &attr))
			&& attr)
		{
			if (!MXD_Strcmp (attr->name, "standalone"))
			{
				if (!MXD_Strcmp (attr->value, "yes"))
					nxml->standalone = 1;

				else
					nxml->standalone = 0;
			}

			else if (!MXD_Strcmp (attr->name, "encoding"))
			{
				nxml->encoding = _mxd_fast_strdup (attr->value);

				if (!nxml->encoding)
				{
					nxml_free_attribute (attr);
					nxml_empty (nxml);

					if (freed)
						_mxd_fast_free (buffer);

					return NXML_ERR_POSIX;
				}
			}

			else
			{

				if (nxml->priv.func)
					nxml->priv.func ("%s: unexpected attribute '%s' (line %d)\n",
					nxml->file ? nxml->file : "", attr->name,
					nxml->priv.line);

				nxml_free_attribute (attr);
				nxml_empty (nxml);

				if (freed)
					_mxd_fast_free (buffer);

				return NXML_ERR_PARSER;
			}

			nxml_free_attribute (attr);
		}

		if (err || _mxd_strncmp (buffer, "?>", 2))
		{
			if (nxml->priv.func)
				nxml->priv.func ("%s expected '?>' (line %d)\n",
				nxml->file ? nxml->file : "", nxml->priv.line);

			nxml_empty (nxml);

			if (freed)
				_mxd_fast_free (buffer);

			return NXML_ERR_PARSER;
		}

		buffer += 2;
		size -= 2;
	}
	root = last = NULL;
	while (!(err = __nxml_parse_get_tag (nxml, &buffer, &size, &tag, &doctype))
		&& (doctype || tag))
	{
		if (doctype)
			continue;

		if (tag->type == NXML_TYPE_ELEMENT && !root)
			root = tag;

		if (last)
			last->next = tag;
		else
			nxml->data = tag;

		last = tag;
	}

	if (err)
	{
		nxml_empty (nxml);

		if (freed)
			_mxd_fast_free (buffer);

		return NXML_ERR_PARSER;
	}

	if (!root)
	{
		if (nxml->priv.func)
			nxml->priv.func ("%s: No root element founded!\n",
			nxml->file ? nxml->file : "");

		nxml_empty (nxml);

		if (freed)
			_mxd_fast_free (buffer);

		return NXML_ERR_PARSER;
	}

	if (freed)
		_mxd_fast_free (buffer);

	nxml->charset_detected = charset;

#if 0
	__nxml_namespace_parse (nxml);
#endif
	return NXML_OK;
}

/* EXTERNAL FUNCTIONS *******************************************************/

nxml_error_t
nxml_parse_buffer (nxml_t * nxml, MXD_CHAR *buffer, MXD_UINT32 size)
{
	if (!buffer || !nxml)
		return NXML_ERR_DATA;

	MXD_Memset( nxml, 0, sizeof( nxml_t ) );
	nxml_empty (nxml);

	_mxd_fast_mem_init( size );

	if (nxml->file)
		_mxd_fast_free (nxml->file);

	nxml->file = _mxd_fast_strdup ("buffer");
	if (!nxml->file)
	{
		nxml_empty (nxml);
		return NXML_ERR_POSIX;
	}

	nxml->size = size;

	return __nxml_parse_buffer (nxml, buffer, size);
}

#if 0

MXD_INT
__nxml_utf8 (MXD_UINT8 **buffer, MXD_UINT32 * size, MXD_INT *byte)
{
	*byte = 1;
	return (MXD_CHAR)**buffer;
}

MXD_INT
__nxml_atoi (MXD_CHAR *str)
{
	MXD_INT ret;
	sscanf (str, "%x", (MXD_UINT *) &ret);
	return ret;
}
#endif

MXD_INT
__nxml_escape_spaces (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size)
{
	/* 
	* Rule [3] - S ::= (#x20 | #x9 | #xD | #xA)+
	*/

	MXD_INT k = 0;

	if (!*size)
		return 0;

	while ((**buffer == 0x20 || **buffer == 0x9 || **buffer == 0xd
		|| **buffer == 0xa) && *size)
	{
		if (**buffer == 0xa && doc->priv.func)
			doc->priv.line++;

		(*buffer)++;
		(*size)--;
		k++;
	}

	return k;
}

MXD_CHAR *
__nxml_get_value (nxml_t * doc, MXD_CHAR **buffer, MXD_UINT32 * size)
{
	MXD_CHAR *attr;
	MXD_INT i;
	MXD_INT quot;

	if (!*size)
		return NULL;

	if (**buffer == '"')
		quot = 1;

	else if (**buffer == '\'')
		quot = 0;

	else
		return NULL;

	(*buffer)++;
	(*size)--;

	i = 0;
	while (((quot && *(*buffer + i) != '"')
		|| (!quot && *(*buffer + i) != '\'')))
	{
		if (*(*buffer + i) == '\n' && doc->priv.func)
			doc->priv.line++;

		i++;
	}

	if (quot && *(*buffer + i) != '"')
		return NULL;

	else if (!quot && *(*buffer + i) != '\'')
		return NULL;
/*
	attr = (MXD_CHAR *) _mxd_fast_malloc (sizeof (MXD_CHAR) * (i + 1));
	if (!attr)
		return NULL;

	MXD_Memcpy (attr, *buffer, i);
*/
	attr = *buffer;
	attr[i] = 0;

	i++;
	(*buffer) += i;
	(*size) -= i;

	return attr;
}

MXD_CHAR *
__nxml_trim (MXD_CHAR *tmp)
{
	/* Trim function: */
	MXD_CHAR *org = tmp;
	MXD_INT i = 0;
	while (tmp[i] == 0x20 || tmp[i] == 0x9 || tmp[i] == 0xd || tmp[i] == 0xa)
		tmp++;

	i = MXD_Strlen (tmp);
	i--;

	while (tmp[i] == 0x20 || tmp[i] == 0x9 || tmp[i] == 0xd || tmp[i] == 0xa)
		i--;

	tmp[i + 1] = 0;

	if( org != tmp )
		MXD_Memcpy( org, tmp, i+2 );
	return org;
	//return _mxd_fast_strdup (tmp);
}

MXD_CHAR *
__nxml_string_no_space (MXD_CHAR *str)
{
	MXD_CHAR *ret;
	MXD_INT i, j;
	MXD_INT q;
	MXD_INT size;

	if (!str)
		return NULL;

	size = MXD_Strlen (str);

	ret = (MXD_CHAR *) _mxd_fast_malloc (sizeof (MXD_CHAR) * (size + 1));
	if (!ret)
		return NULL;

	for (q = i = j = 0; i < size; i++)
	{
		if (*(str + i) == 0xd)
			continue;

		if (*(str + i) == 0xa || *(str + i) == 0x9 || *(str + i) == 0x20)
		{
			if (!q)
			{
				q = 1;
				ret[j++] = *(str + i);
			}
		}

		else
		{
			q = 0;
			ret[j++] = *(str + i);
		}
	}

	ret[j] = 0;

	return ret;
}

__nxml_string_t *
__nxml_string_new (void)
{
	__nxml_string_t *st;

	st = (__nxml_string_t *) _mxd_calloc (1, sizeof (__nxml_string_t));
	if (!st)
		return NULL;

	return st;
}

MXD_CHAR *
__nxml_string_free (__nxml_string_t * st)
{
	MXD_CHAR *ret;

	if (!st)
		return NULL;

	ret = st->string;
	_mxd_fast_free (st);

	return ret;
}

MXD_INT
__nxml_string_add (__nxml_string_t * st, MXD_CHAR *what, MXD_UINT32 size)
{
	MXD_CHAR* pNewStr;
	if (!st || !*what)
		return 1;

	if (size <= 0)
		size = MXD_Strlen (what);

	if (!st->size)
	{
		st->string = (MXD_CHAR *) _mxd_fast_malloc (sizeof (MXD_CHAR) * (size + 1));
		if (!st->string)
			return 1;
	}
	else
	{
		pNewStr = _mxd_fast_malloc( sizeof (MXD_CHAR) * (size + st->size + 1) );
		if( !pNewStr )
			return 1;
		MXD_Strcpy( pNewStr, st->string );
		_mxd_fast_free( st->string );
		st->string = pNewStr;
	}

	MXD_Memcpy (st->string + st->size, what, size);
	st->size += size;
	st->string[st->size] = 0;

	return 0;
}

#if 0
struct __nxml_data_ns_t
{
	nxml_namespace_t *ns;
	struct __nxml_data_ns_t *next;
};

static void
__nxml_namespace_free_item (nxml_data_t * e)
{
	nxml_namespace_t *ns;
	nxml_data_t *child;

	while (e->ns_list)
	{
		ns = e->ns_list->next;

		if (e->ns_list->prefix)
			_mxd_fast_free (e->ns_list->prefix);

		if (e->ns_list->ns)
			_mxd_fast_free (e->ns_list->ns);

		_mxd_fast_free (e->ns_list);

		e->ns_list = ns;
	}

	e->ns = NULL;

	child = e->children;
	while (child)
	{
		__nxml_namespace_free_item (child);
		child = child->next;
	}
}

static void
__nxml_namespace_free (nxml_t * nxml)
{
	nxml_data_t *e;

	e = nxml->data;
	while (e)
	{
		__nxml_namespace_free_item (e);

		e = e->next;
	}
}

MXD_INT
__nxml_namespace_parse_add (nxml_data_t * data, MXD_CHAR *prefix, MXD_CHAR *namespc)
{
	nxml_namespace_t *ns;

	if (!(ns = (nxml_namespace_t *) _mxd_calloc (1, sizeof (nxml_namespace_t))))
		return 1;

	if (prefix && !(ns->prefix = _mxd_fast_strdup (prefix)))
	{
		_mxd_fast_free (ns);
		return 1;
	}

	if (!(ns->ns = _mxd_fast_strdup (namespc)))
	{
		if (ns->prefix)
			_mxd_fast_free (ns->prefix);
		_mxd_fast_free (ns);
		return 1;
	}

	ns->next = data->ns_list;
	data->ns_list = ns;

	return 0;
}

static MXD_INT
__nxml_namespace_find_item (nxml_t * nxml, nxml_data_t * e)
{
	nxml_data_t *child;
	nxml_attr_t *att;

	att = e->attributes;
	while (att)
	{
		if (!MXD_Strcmp (att->name, "xmlns"))
		{
			if (__nxml_namespace_parse_add (e, NULL, att->value))
			{
				__nxml_namespace_free (nxml);
				return 1;
			}
		}
		else if (!_mxd_strncmp (att->name, "xmlns:", 6))
		{
			if (__nxml_namespace_parse_add (e, att->name + 6, att->value))
			{
				__nxml_namespace_free (nxml);
				return 1;
			}
		}

		att = att->next;
	}

	child = e->children;
	while (child)
	{
		if (child->type == NXML_TYPE_ELEMENT)
			__nxml_namespace_find_item (nxml, child);
		child = child->next;
	}

	return 0;
}

static MXD_INT
__nxml_namespace_find (nxml_t * nxml)
{
	nxml_data_t *e;

	e = nxml->data;
	while (e)
	{
		if (e->type == NXML_TYPE_ELEMENT)
			__nxml_namespace_find_item (nxml, e);
		e = e->next;
	}

	return 0;

}

static void
__nxml_namespace_associate_attribute (struct __nxml_data_ns_t *list,
									  nxml_attr_t * e)
{
	MXD_INT i;
	MXD_INT len = MXD_Strlen (e->name);
	MXD_INT k;

	for (i = k = 0; i < len; i++)
		if (e->name[i] == ':')
		{
			k = i;
			break;
		}

		if (!k)
		{
			while (list)
			{
				if (!list->ns->prefix)
				{
					e->ns = list->ns;
					return;
				}
				list = list->next;
			}

			return;
		}

		else
		{
			while (list)
			{
				if (list->ns->prefix && !_mxd_strncmp (list->ns->prefix, e->name, k))
				{
					MXD_CHAR *a = _mxd_fast_strdup (e->name + MXD_Strlen (list->ns->prefix) + 1);

					if (!a)
						return;

					_mxd_fast_free (e->name);
					e->name = a;

					e->ns = list->ns;
					return;
				}
				list = list->next;
			}
		}
}

static void
__nxml_namespace_associate_item (struct __nxml_data_ns_t *list,
								 nxml_data_t * e)
{
	MXD_INT i;
	MXD_INT len;
	MXD_INT k;
	nxml_attr_t *attr;

	attr = e->attributes;
	while (attr)
	{
		__nxml_namespace_associate_attribute (list, attr);
		attr = attr->next;
	}

	len = MXD_Strlen (e->value);

	for (i = k = 0; i < len; i++)
		if (e->value[i] == ':')
		{
			k = i;
			break;
		}

		if (!k)
		{
			while (list)
			{
				if (!list->ns->prefix)
				{
					e->ns = list->ns;
					return;
				}
				list = list->next;
			}

			return;
		}

		else
		{
			while (list)
			{
				if (list->ns->prefix && !_mxd_strncmp (list->ns->prefix, e->value, k))
				{
					MXD_CHAR *a = _mxd_fast_strdup (e->value + MXD_Strlen (list->ns->prefix) + 1);

					if (!a)
						return;

					_mxd_fast_free (e->value);
					e->value = a;

					e->ns = list->ns;
					return;
				}
				list = list->next;
			}
		}
}

static void
__nxml_namespace_associate (struct __nxml_data_ns_t **list,
							nxml_data_t * root)
{
	nxml_data_t *e;
	nxml_namespace_t *ns;
	struct __nxml_data_ns_t *tmp, *old;

	ns = root->ns_list;
	while (ns)
	{
		if (!(tmp = (struct __nxml_data_ns_t*)_mxd_calloc (1, sizeof (struct __nxml_data_ns_t))))
			return;

		tmp->ns = ns;
		tmp->next = (*list);
		(*list) = tmp;

		ns = ns->next;
	}

	__nxml_namespace_associate_item (*list, root);

	e = root->children;
	while (e)
	{
		if (e->type == NXML_TYPE_ELEMENT)
			__nxml_namespace_associate (list, e);

		e = e->next;
	}

	ns = root->ns_list;
	while (ns)
	{
		tmp = *list;
		old = NULL;

		while (tmp)
		{
			if (tmp->ns == ns)
			{
				if (old)
					old->next = tmp->next;
				else
					*list = tmp->next;

				_mxd_fast_free (tmp);
				break;
			}

			old = tmp;
			tmp = tmp->next;
		}

		ns = ns->next;
	}
}

static void
__nxml_namespace_connect (nxml_t * nxml)
{
	nxml_data_t *e;
	struct __nxml_data_ns_t *list = NULL;

	e = nxml->data;
	while (e)
	{
		if (e->type == NXML_TYPE_ELEMENT)
			__nxml_namespace_associate (&list, e);

		e = e->next;
	}
}

void
__nxml_namespace_parse (nxml_t * nxml)
{
	__nxml_namespace_free (nxml);

	if (__nxml_namespace_find (nxml))
		return;

	__nxml_namespace_connect (nxml);
}
#endif

static void __nxml_private_free (__nxml_private_t * priv);
static void __nxml_entity_free (__nxml_private_t * priv);

nxml_error_t
nxml_free_data (nxml_data_t * data)
{
	//nxml_namespace_t *namespc;
	nxml_attr_t *attr;
	nxml_data_t *tmp;
	void *old;

	if (!data)
		return NXML_ERR_DATA;

	//if (data->value)
	//  _mxd_fast_free (data->value);
#if 0
	namespc = data->ns_list;
	while (namespc)
	{
		old = namespc;
		namespc = namespc->next;

		nxml_free_namespace ( (nxml_namespace_t *)old);
	}
#endif
	attr = data->attributes;
	while (attr)
	{
		old = attr;
		attr = attr->next;

		nxml_free_attribute ((nxml_attr_t *)old);
	}

	tmp = data->children;
	while (tmp)
	{
		old = tmp;
		tmp = tmp->next;

		nxml_free_data ((nxml_data_t *)old);
	}

	_mxd_fast_free (data);

	return NXML_OK;
}

nxml_error_t
nxml_free_attribute (nxml_attr_t * t)
{
	if (!t)
		return NXML_ERR_DATA;

	if (t->name)
		_mxd_fast_free (t->name);

	if (t->value)
		_mxd_fast_free (t->value);

	_mxd_fast_free (t);

	return NXML_OK;
}

nxml_error_t
nxml_free_namespace (nxml_namespace_t * t)
{
	if (!t)
		return NXML_ERR_DATA;

	if (t->prefix)
		_mxd_fast_free (t->prefix);

	if (t->ns)
		_mxd_fast_free (t->ns);

	_mxd_fast_free (t);

	return NXML_OK;
}

nxml_error_t
nxml_free_doctype (nxml_doctype_t * doctype)
{
	nxml_doctype_t *tmp;

	if (!doctype)
		return NXML_ERR_DATA;

	while (doctype)
	{
		if (doctype->value)
			_mxd_fast_free (doctype->value);

		if (doctype->name)
			_mxd_fast_free (doctype->name);

		tmp = doctype;
		doctype = doctype->next;

		_mxd_fast_free (tmp);
	}

	return NXML_OK;
}

nxml_error_t
nxml_free (nxml_t * data)
{
	if (!data)
		return NXML_ERR_DATA;

	nxml_empty (data);

	__nxml_private_free (&data->priv);

	_mxd_fast_free (data);

	return NXML_OK;
}

nxml_error_t
nxml_empty (nxml_t * data)
{
	nxml_data_t *t, *old;
	__nxml_private_t priv;

	if (!data)
		return NXML_ERR_DATA;

	if (data->file)
		_mxd_fast_free (data->file);

	if (data->encoding)
		_mxd_fast_free (data->encoding);

	/* I must free the doctype, I must not empty only! */
	if (data->doctype)
		nxml_free_doctype (data->doctype);

	t = data->data;
	while (t)
	{
		old = t;
		t = t->next;
		nxml_free_data (old);
	}

	__nxml_entity_free (&data->priv);

	MXD_Memcpy (&priv, &data->priv, sizeof (__nxml_private_t));
	MXD_Memset (data, 0, sizeof (nxml_t));
	MXD_Memcpy (&data->priv, &priv, sizeof (__nxml_private_t));

	_mxd_fast_mem_destory();

	return NXML_OK;
}

static void
__nxml_entity_free (__nxml_private_t * priv)
{
	__nxml_entity_t *entity;

	if (!priv)
		return;

	while (priv->entities)
	{
		entity = priv->entities;
		priv->entities = priv->entities->next;

		if (entity->entity)
			_mxd_fast_free (entity->entity);

		if (entity->name)
			_mxd_fast_free (entity->name);

		_mxd_fast_free (entity);
	}
}

static void
__nxml_private_free (__nxml_private_t * priv)
{
	if (!priv)
		return;

	if (priv->proxy)
		_mxd_fast_free (priv->proxy);

	if (priv->proxy_authentication)
		_mxd_fast_free (priv->proxy_authentication);

	if (priv->certfile)
		_mxd_fast_free (priv->certfile);

	if (priv->password)
		_mxd_fast_free (priv->password);

	if (priv->cacert)
		_mxd_fast_free (priv->cacert);

	if (priv->authentication)
		_mxd_fast_free (priv->authentication);

	if (priv->user_agent)
		_mxd_fast_free (priv->user_agent);

	__nxml_entity_free (priv);
}

MXD_CHAR *
nxml_strerror (nxml_t * nxml, nxml_error_t err)
{
	switch (err)
	{
	case NXML_OK:
		return "Success";

	case NXML_ERR_PARSER:
		return "Parser error";

	case NXML_ERR_DATA:
		return "No correct paramenter in the function";
	}
	return "";
}

nxml_error_t
nxml_line_error (nxml_t * nxml, MXD_INT *line)
{
	if (!nxml || !line)
		return NXML_ERR_DATA;

	*line = nxml->priv.line;

	return NXML_OK;
}

nxml_error_t
nxml_root_element (nxml_t * nxml, nxml_data_t ** data)
{
	nxml_data_t *tmp;

	if (!data || !nxml)
		return NXML_ERR_DATA;

	tmp = nxml->data;
	while (tmp)
	{

		if (tmp->type == NXML_TYPE_ELEMENT)
			break;

		tmp = tmp->next;
	}

	*data = tmp;

	return NXML_OK;
}

nxml_error_t
nxml_doctype_element (nxml_t * nxml, nxml_doctype_t ** data)
{
	if (!data || !nxml)
		return NXML_ERR_DATA;

	*data = nxml->doctype;
	return NXML_OK;
}

nxml_error_t
nxml_get_string (nxml_data_t * data, MXD_CHAR **string)
{
	if (!data || !string)
		return NXML_ERR_DATA;

	if (data->type == NXML_TYPE_TEXT)
		*string = _mxd_fast_strdup (data->value);

	else if (data->type == NXML_TYPE_ELEMENT)
	{
		nxml_data_t *tmp;

		tmp = data->children;
		*string = NULL;

		while (tmp)
		{
			if (tmp->type == NXML_TYPE_TEXT)
			{
				*string = _mxd_fast_strdup (tmp->value);
				break;
			}
			tmp = tmp->next;
		}
	}
	else
		*string = NULL;

	return NXML_OK;
}


nxml_data_t * nxml_find_element( nxml_t * nxml, nxml_data_t * data, const MXD_CHAR *name )
{
	nxml_data_t *tmp;

	if (!nxml || !name )
		return NULL;

	if (data && data->type != NXML_TYPE_ELEMENT)
		return NULL;

	if (data)
		tmp = data->children;
	else
		tmp = nxml->data;

	while (tmp)
	{
		if (tmp->type == NXML_TYPE_ELEMENT && !MXD_Strcmp (tmp->value, name))
			return tmp;

		tmp = tmp->next;
	}

	return NULL;
}

nxml_attr_t * nxml_find_attribute( nxml_data_t * data, const MXD_CHAR *name )
{
	nxml_attr_t *tmp;

	if (!data || !name )
		return NULL;

	if (data->type != NXML_TYPE_ELEMENT)
		return NULL;

	tmp = data->attributes;

	while (tmp)
	{
		if (!MXD_Strcmp (tmp->name, name))
			return tmp;

		tmp = tmp->next;
	}

	return NULL;
}

#if 0
nxml_error_t
nxml_find_namespace (nxml_data_t * data, MXD_CHAR *name,
					 nxml_namespace_t ** namespc)
{
	nxml_namespace_t *tmp;

	if (!data || !name || !namespc)
		return NXML_ERR_DATA;

	if (data->type != NXML_TYPE_ELEMENT)
	{
		*namespc = NULL;
		return NXML_OK;
	}

	tmp = data->ns_list;

	while (tmp)
	{
		if (!MXD_Strcmp (tmp->ns, name))
		{
			*namespc = tmp;
			return NXML_OK;
		}

		tmp = tmp->next;
	}

	*namespc = NULL;
	return NXML_OK;
}
#endif

nxml_data_t * GetChildElement( nxml_data_t * data, const MXD_CHAR *name )
{
	nxml_data_t *tmp;

	if ( !name )
		return NULL;

	if (data && data->type != NXML_TYPE_ELEMENT)
		return NULL;

	tmp = data->children;

	while (tmp)
	{
		if (tmp->type == NXML_TYPE_ELEMENT && !MXD_Strcmp (tmp->value, name))
			return tmp;

		tmp = tmp->next;
	}

	return NULL;
}

nxml_data_t * GetNextElement( nxml_data_t * data, const MXD_CHAR *name )
{
	nxml_data_t *tmp;

	if ( !name )
		return NULL;

	if (data && data->type != NXML_TYPE_ELEMENT)
		return NULL;

	tmp = data->next;

	while (tmp)
	{
		if (tmp->type == NXML_TYPE_ELEMENT && !MXD_Strcmp (tmp->value, name))
			return tmp;

		tmp = tmp->next;
	}

	return NULL;
}

MXD_UINT CountChildren( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	MXD_UINT nCount = 0;
	nxml_data_t* pChild = GetChildElement( element, pChildName );
	while( pChild  )
	{
		if( MXD_Strcmp( pChild->value, pChildName ) == 0 )
			nCount++;
		pChild = pChild->next;
	}
	return nCount;
}

MXD_UINT GetAttibuteIntValue( nxml_data_t *element, const MXD_CHAR* pAttrName )
{
	if( !nxml_find_attribute( element, pAttrName ) )
		return 0;
	return atoi( nxml_find_attribute( element, pAttrName )->value );
}

MXD_UINT GetChildIntValue( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	if( !GetChildText( element, pChildName ) )
		return 0;
	return atoi( GetChildText( element, pChildName ) );
}

#define HexCharToInt( hex ) \
	( (hex >= '0' && hex <= '9') ? (hex - '0') : ( (hex >= 'a' && hex <= 'f') ? (hex - 'a' + 10) : ( (hex >= 'A'  && hex <= 'F') ? (hex - 'A' + 10) : 0) ) )

MXD_UINT GetChildHexValue( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	const MXD_CHAR* pText = GetChildText( element, pChildName );
	if( !pText )
		return 0;
	return ( HexCharToInt(pText[2]) << 4) + HexCharToInt(pText[3]);
}

MXD_INT GetChildBoolValue( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	if( !GetChildText( element, pChildName ) )
		return 0;
	return atoi( GetChildText( element, pChildName ) );
}

MXD_INT GetChildBoolValue2( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	if( !GetChildText( element, pChildName ) )
		return 0;
	return MXD_Strcmp( GetChildText( element, pChildName ), "true" ) == 0;
}

MXD_CHAR* CloneChildText( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	MXD_CHAR* ptmp;
	if( !GetChildText( element, pChildName ) )
		return 0;
	ptmp = (MXD_CHAR*) MXD_Malloc( MXD_Strlen( GetChildText( element, pChildName ) ) + 1  );
	MXD_Strcpy( ptmp, GetChildText( element, pChildName ) );
	return ptmp;
}

MXD_INT GetAttibuteLangValue( nxml_data_t *element, const MXD_CHAR* pAttrName )
{
	if( !nxml_find_attribute( element, pAttrName ) )
		return 0;
	if( MXD_Strcmp( nxml_find_attribute( element, pAttrName )->value, "zho" ) == 0 )
		return 0;
	else
		return 1;
}

MXD_INT GetChildLangValue( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	if( !GetChildText( element, pChildName ) )
		return 0;
	if( MXD_Strcmp( GetChildText( element, pChildName ), "zho" ) == 0 )
		return 0;
	else
		return 1;
}

const MXD_CHAR* GetChildText( nxml_data_t *element, const MXD_CHAR* pChildName )
{
	if( !GetChildElement( element, pChildName ) )
		return 0;
	if( !GetChildElement( element, pChildName )->children )
		return 0;
	return GetChildElement( element, pChildName )->children->value;
}

MXD_INT GetOptIndexFromChildValue( nxml_data_t *element, const MXD_CHAR* pChildName, const MXD_CHAR* pOption1, const MXD_CHAR* pOption2, const MXD_CHAR* pOption3, const MXD_CHAR* pOption4, const MXD_CHAR* pOption5,const MXD_CHAR* pOption6, const MXD_CHAR* pOption7 )
{
	const MXD_CHAR* pChildText = GetChildText( element, pChildName );
	if( MXD_Strcmp( pOption1, pChildText ) == 0 )
		return 0;
	if( MXD_Strcmp( pOption2, pChildText ) == 0 )
		return 1;
	if( MXD_Strcmp( pOption3, pChildText ) == 0 )
		return 2;
	if( MXD_Strcmp( pOption4, pChildText ) == 0 )
		return 3;
	if( MXD_Strcmp( pOption5, pChildText ) == 0 )
		return 4;
	if( MXD_Strcmp( pOption6, pChildText ) == 0 )
		return 5;	
	if( MXD_Strcmp( pOption7, pChildText ) == 0 )
		return 6;	
	return -1;
}

/* EOF */
